#!/bin/bash
#-----------------------------------------------------------------------#
#			      NSS Script				#
#			    Vallée Cédric				#
#			      17/10/2011		
#-----------------------------------------------------------------------#


#-----------------------------------------------------------------------#
#			 Global Variables				#
#-----------------------------------------------------------------------#

char=( 1 2 3 4 8 9 0 b d f h n s A H M ) #The set of characters that'll be used in the password Generation
varTab=( 0 0 0 ) #the actual index of the generated password char // ps: the generation is directly binded to the length of this array (generates 1-ArrayLength size password) 

nextInt=0 #Useless xD
limitInc=false #Stopping boolean of the generation
result="" #the actual generated pwd

#The idea of the following functions is to get one different generated password each time you call giveString
#They're generated by progressive incrementation through the char array

#-----------------------------------------------------------------------#
#			 Function Declaration				#
#-----------------------------------------------------------------------#


# Reset function
function resetGiveString() {
	varTab=( 0 0 0 )
	limitInc=false
}

# Starting function
# 1st param : int => the length of the desired password (between 1 and the length of varTab)
# return : string => password stored into $result
function giveString() {
	result=""
	let "tmp=$1-1"
	giveString2 $tmp
	increment 0 $1 #Once the password as been calculated we increase the counter for the next one
}

# Recursive function
# 1st param : int => the length of the desired password (between 1 and the length of varTab)
# return : string => password stored into $result
function giveString2() {
	#Stopping condition
	# if the asked length is 0 then put the character at the end of result
	if [ $1 -eq 0 ]; then
		tmp=${varTab[$1]}
		tmp=${char[$tmp]}
		result=$result$tmp
	fi
	
	#if not we access the current asked character stored it in result and recall the same function (decrementing the asked length)
	if [ $1 -gt 0 ]; then
		tmp=${varTab[$1]}
		tmp=${char[$tmp]}
		result=$result$tmp
		let "tmp2=$1-1"
		giveString2 $tmp2
	fi
}

#Recursive function
# 1st param : int => the index of varTab which need to be incremented
# 2st param : int => the limit of the potential incrementation
# no return
# Checking of incrementation possibility through $limitInc
function increment() {
	#stopping condition
	# if the asked index doesn't exist or if it exceed the asked length
	if [[ $1 -gt ${#varTab[*]} ]] || [[ $1 -ge $2 ]]; then
		#if one of theses condition is reached, it means than there's no more possible password so we stop
		limitInc=true
		return
	fi
	
	#increase the index
	let "varTab[$1]=${varTab[$1]}+1"

	#if it surpass the length of the char array then we set it to 0 and ask for an incrementation of the upper index
	if [[ ${varTab[$1]} -ge ${#char[*]} ]]; then
		showBar $n $nbTest
		varTab[$1]=0
		let "tmp=$1+1"
		increment $tmp $2
	fi
}

#From internet and modified by myself
#Aim : Show the progression of an activity through a progress bar
#1st param : int => actual position
#2nd param : int => final number to reach
# PS: the prompt variable allow me to store the different user information over the time and the change
function showBar {
	#Calculation of % float and then conversion back to int
	percDone=$(echo 'scale=2;'$1/$2*100 | bc)
	let "perc=$1*100/$2"
	let "barTmp=$(tput cols)-10" #Allow the bar to resize in function of the console size
	barLen=$(echo 'scale=2;'$1/$2*$barTmp | bc)
	barLen=${barLen/\.*}
	bar=''
	fills=''
	if [[ $barLen != [0-9]* ]]; then
		barLen=0
	fi

	for (( b=0; b<$barLen; b++ ))
	do
		bar=$bar"="
	done
	blankSpaces=$(echo $(($barTmp-$barLen)))
	
	for (( f=0; f<$blankSpaces; f++ ))
	do
		fills=$fills"_"
	done
	clear #nettoyage de la console puis affichage
	echo -e $prompt
	echo '['$bar'>'$fills'] - '$perc'%'
}

#-----------------------------------------------------------------------#
#			 Script beginning				#
#-----------------------------------------------------------------------#

if [ $# -ne 1 ] || [ $1 = '-h' ]
then
	echo -e "\tFirst arg : DES password file"
	exit
fi

if [ -e $1 ]; then
	echo -e "Le fichier $1 est invalide"	
	exit
fi

#Regular expression analysing and parsing the name and the encrypted DES password
regex='^([[:alnum:]]*):(.*)$'

#Number of line of $1 => TotalUser Number
let "TotalUsr=$(cat $1 | wc -l)" 

#calculation of the maximal number of password possible to generate
#E0 = 0 En= E(n-1)*LG + LG
#Nmax being the length of the varTab array
nbTest=0
lg=${#char[*]}
for i in "${varTab[@]}"
do
	let "nbTest=$nbTest * $lg + $lg"
done

#Initialazation of the loop
prompt=""
nbUsr=0
for LINE in `cat $1`
do
   #Check if the line match a Usr:Password expression
   if [[ "$LINE" =~ $regex ]]
   then
	#Extraction of the usr and password part
	(( nbUsr++ ))
	Usr="${BASH_REMATCH[1]}"
	prompt="$prompt\nResearching password for $Usr ($nbUsr on ${#PTXT[@]} users)"
	Pass="${BASH_REMATCH[2]}"

	#Parameters initialization of the generation password loop
	trouve=false
	i=1
	n=0
	resetGiveString
	until [[ $i -gt ${#varTab[*]}  ]]; do 
		(( n++ ))
		giveString $i
		test=$result
		#If we can't generate anymore password then we need to increase the length and retry
		if $limitInc; then
			(( i++ ))
			resetGiveString
			giveString $i
			test=$result
			#echo "if END $i/$test"
			showBar $n $nbTest
		fi

		#Hash generation and comparation
		newpass=$(perl -e'print crypt($ARGV[0], $ARGV[1])' $test $Pass)

		if [[ "$Pass" =~ "$newpass" ]] 
			then
			prompt="$prompt\nPassword Find for $Usr : $test"
			echo "$Usr : $test : $Pass / $newpass" >>pass.txt
			trouve=true
			break
		fi
	done

   else
       echo "Fail $LINE doesn't match"
   fi
   echo "Research for $Usr made : Password find = $trouve"
   prompt="$prompt\n$n Combinations studied"
done
echo "The results are stored in pass.txt"
# $SECONDS = elapsed time
let "t= $SECONDS / $nbUsr"
echo "The average time per user's password computation is $t s"
